package hygprs

import (
	"bytes"
	"encoding/binary"
	"encoding/hex"
	"fmt"
	"github.com/axgle/mahonia"
	"regexp"
	"strconv"
	"strings"
	"unsafe"
)

/*
字节切片与其他类型的转换
*/

func ToUint16(v []byte) uint16 {
	return uint16(v[0])*256 + uint16(v[1])
}

func ToUint16Little(v []byte) uint16 {
	return uint16(v[1])*256 + uint16(v[0])
}

func FromUint16(v uint16) []byte {
	res := make([]byte, 2)
	res[1] = byte(v % 256)
	res[0] = byte(v / 256)
	return res
}

func ToUint32(v []byte) uint32 {
	return uint32(v[0])*256*256*256 + uint32(v[1])*256*256 + uint32(v[2])*256 + uint32(v[3])
}
func ToUint32Little(v []byte) uint32 {
	return uint32(v[3])*256*256*256 + uint32(v[2])*256*256 + uint32(v[1])*256 + uint32(v[0])
}

func FromUint32(v uint32) []byte {
	res := make([]byte, 4)
	res[3] = byte(v % 256)
	v = v / 256
	res[2] = byte(v % 256)
	v = v / 256
	res[1] = byte(v % 256)
	res[0] = byte(v / 256)
	return res
}

// 将不固定长度的字节转换成整数 大端
func ToInt(v []byte) int {
	i := 0
	for _, b := range v {
		i = i*256 + int(b)
	}
	return i
}

// 将不固定长度的字节转换成整数 小端(倒序遍历)
func ToIntLittle(v []byte) int {
	i := 0
	l := len(v) - 1
	for k, _ := range v {
		i = i*256 + int(v[l-k])
	}
	return i
}

// 将整数转换成不固定长度的字节
func FromInt(v int) []byte {
	s := make([]byte, 0, 8)
	for v != 0 {
		s = append(s, byte(v%256))
		v /= 256
	}
	res := make([]byte, len(s))
	for i := 0; i < len(s); i++ {
		res[len(s)-i] = s[i]
	}
	return res
}

// 整数转成指定长度字节数组  大端
func IntToBytes(n int, b int) ([]byte, error) {
	switch b {
	case 1:
		tmp := int8(n)
		bytesBuffer := bytes.NewBuffer([]byte{})
		binary.Write(bytesBuffer, binary.BigEndian, &tmp)
		return bytesBuffer.Bytes(), nil
	case 2:
		tmp := int16(n)
		bytesBuffer := bytes.NewBuffer([]byte{})
		binary.Write(bytesBuffer, binary.BigEndian, &tmp)
		return bytesBuffer.Bytes(), nil
	case 3, 4:
		tmp := int32(n)
		bytesBuffer := bytes.NewBuffer([]byte{})
		binary.Write(bytesBuffer, binary.BigEndian, &tmp)
		return bytesBuffer.Bytes(), nil
	case 8:
		tmp := int64(n)
		bytesBuffer := bytes.NewBuffer([]byte{})
		binary.Write(bytesBuffer, binary.BigEndian, &tmp)
		return bytesBuffer.Bytes(), nil
	}
	return nil, fmt.Errorf("IntToBytes b param is invaild")
}

// 多个切片按照顺序合并一起
func SlicesAppend(bs ...[]byte) []byte {
	var all []byte
	for _, b := range bs {
		all = append(all, b...)
	}
	return all
}

func ToIPAddr(v []byte) string {
	bs := v[4:6]
	return fmt.Sprintf("%d.%d.%d.%d:%d", v[3], v[2], v[1], v[0], ToUint16([]byte{bs[1], bs[0]}))
}

func FromIPAddr(ip string) []byte {
	v := make([]byte, 4, 6)
	var port uint16
	_, err := fmt.Sscanf(ip, "%d.%d.%d.%d:%d", &v[3], &v[2], &v[1], &v[0], &port)
	if err != nil {
		fmt.Println(err)
	}
	bs := FromUint16(port)
	return append(v, bs[1], bs[0])
}

func ToGBK(s string) string {
	dec := mahonia.NewEncoder("GBK")
	return dec.ConvertString(s)
}

// 高效的字节流转字符串
func B2Str(b []byte) string {
	return *(*string)(unsafe.Pointer(&b))
}

// 解析BCD码为字符串
func Bcd2Number(bcd []byte) string {
	var number string
	for _, i := range bcd {
		number += fmt.Sprintf("%02X", i)
	}
	pos := strings.LastIndex(number, "F")
	if pos == 8 {
		return "0"
	}
	return number[pos+1:]
}

// 数字转BCD码
func Number2bcd(number string) []byte {
	var rNumber = number
	for i := 0; i < 8-len(number); i++ {
		rNumber = "f" + rNumber
	}
	bcd := Hex2Byte(rNumber)
	return bcd
}
func Hex2Byte(str string) []byte {
	slen := len(str)
	bHex := make([]byte, len(str)/2)
	ii := 0
	for i := 0; i < len(str); i = i + 2 {
		if slen != 1 {
			ss := string(str[i]) + string(str[i+1])
			bt, _ := strconv.ParseInt(ss, 16, 32)
			bHex[ii] = byte(bt)
			ii = ii + 1
			slen = slen - 2
		}
	}
	return bHex
}

// 转换成16进制格式的字符串，大写，中间加空格
func ToHexString(data []byte) string {
	s := hex.EncodeToString(data)
	s = strings.ToUpper(s)
	r := regexp.MustCompile("([0-9A-F]{2})")
	return r.ReplaceAllString(s, "$1 ")
}

func FromHexString(str string) []byte {
	data, _ := hex.DecodeString(strings.ReplaceAll(str, " ", ""))
	return data
}

// 计算校验和
func CheckSum(data []byte) uint32 {
	sum := uint32(0)
	for _, b := range data {
		sum += uint32(b)
	}
	return sum
}

// 将数据复制到新的切片
func Copy(data []byte) []byte {
	dst := make([]byte, len(data))
	copy(dst, data)
	return dst
}
